﻿namespace MicroCloud.Api.Identity.Areas.Admin.Controllers.Identity
{
    /// <summary>
    /// 用户管理
    /// </summary>
    [Description("用户管理")]
    [ModuleInfo(Code = "User", Name = "用户管理", OrderNo = 4, Position = "Identity", PositionName = "认证模块")]
    public class UserController : AdminControllerBase
    {
        #region 属性
        /// <summary>
        /// 获取 身份认证业务契约
        /// </summary>
        protected IIdentityContract IdentityContract => ServiceProvider.GetService<IIdentityContract>();
        
        /// <summary>
        /// 获取 用户管理器
        /// </summary>
        protected UserManager<User> UserManager => ServiceProvider.GetService<UserManager<User>>();

        /// <summary>
        /// 获取 用户仓储模型
        /// </summary>
        protected IRepository<User, long> UserRepository => ServiceProvider.GetService<IRepository<User, long>>();

        /// <summary>
        /// 获取 用户证照仓储模型
        /// </summary>
        protected IRepository<UserPortfolio, long> UserPortfolioRepository => ServiceProvider.GetService<IRepository<UserPortfolio, long>>();

        /// <summary>
        /// 获取 用户详情仓储模型
        /// </summary>
        protected IRepository<UserDetail, long> UserDetailRepository => ServiceProvider.GetService<IRepository<UserDetail, long>>();

        #endregion

        #region Action
        /// <summary>
        /// 读取用户
        /// </summary>
        /// <param name="request">分页请求</param>
        /// <returns>用户列表信息</returns>
        [HttpPost]
        [ModuleInfo]
        [Description("读取")]
        public virtual PageData<UserOutputDto> Read(PageRequest request)
        {
            Check.NotNull(request, nameof(request));
            IFunction function = this.GetExecuteFunction();

            Func<User, bool> updateFunc = FilterService.GetDataFilterExpression<User>(null, DataAuthOperation.Update).Compile();
            Func<User, bool> deleteFunc = FilterService.GetDataFilterExpression<User>(null, DataAuthOperation.Delete).Compile();
            Expression<Func<User, bool>> predicate = FilterService.GetExpression<User>(request.FilterGroup);

            PageResult<UserOutputDto> page;
            using (var scope = ServiceProvider.CreateScope())
            {
                var userRepository = scope.ServiceProvider.GetService<IRepository<User, long>>();

                page = CacheService.ToPageCache(UserManager.Users, predicate, request.PageCondition, m => new
                {
                    U = m,
                    D = m.Detail,
                    Roles = m.UserRoles.Select(n => n.Role.Name)
                }, function).ToPageResult(data => data.Select(m => new UserOutputDto(m.U, m.D)
                {
                    Roles = m.Roles.ToArray(),
                    Updatable = updateFunc(m.U),
                    Deletable = deleteFunc(m.U)
                }).ToArray());

                //page = UserManager.Users.ToPage(predicate, request.PageCondition, m => new
                //{
                //    U = m,
                //    D = m.Detail,
                //    Roles = m.UserRoles.Select(n => n.Role.Name)
                //}).ToPageResult(data => data.Select(m => new UserOutputDto(m.U, m.D)
                //{
                //    Roles = m.Roles.ToArray(),
                //    Updatable = updateFunc(m.U),
                //    Deletable = deleteFunc(m.U)
                //}).ToArray());

            }

            return page.ToPageData();
        }

        /// <summary>
        /// 读取用户节点
        /// </summary>
        /// <param name="group">筛选条件组</param>
        /// <returns></returns>
        [HttpPost]
        [ModuleInfo]
        [Description("读取节点")]
        public virtual UserNode[] ReadNode(FilterGroup group)
        {
            Check.NotNull(group, nameof(group));
            IFunction function = this.GetExecuteFunction();
            Expression<Func<User, bool>> exp = FilterService.GetExpression<User>(group);
            //ListNode[] nodes = CacheService.ToCacheArray<User, ListNode>(UserManager.Users, exp, m => new ListNode()
            //{
            //    Id = m.Id,
            //    Name = m.NickName,
            //}, function);
            //return nodes;
            UserNode[] nodes = CacheService.ToCacheArray<User, UserNode>(UserManager.Users, exp, function);
            return nodes;
        }

        /// <summary>
        /// 获取用户
        /// </summary>
        /// <param name="userIds">用户编号</param>
        /// <returns>用户DTO</returns>
        [HttpPost]
        [ModuleInfo]
        [Description("获取")]
        public virtual List<UserDto> GetUsers(params long[] userIds)
        {
            Check.NotNull(userIds, nameof(userIds));

            IFunction function = this.GetExecuteFunction();

            Expression<Func<User, bool>> exp = m => userIds.Contains(m.Id);
            List<UserDto> dtos = CacheService.ToCacheList(IdentityContract.Users, exp, u => new UserDto(u, u.Portfolio, u.Detail), function);

            return dtos;
        }

        /// <summary>
        /// 获取用户树
        /// </summary>
        /// <param name="userIds">用户编号</param>
        /// <returns>用户树数据</returns>
        [HttpPost]
        [ModuleInfo]
        [Description("获取树")]
        public virtual List<UserNode> GetUserNodes(params long[] userIds)
        {
            Check.NotNull(userIds, nameof(userIds));

            IFunction function = this.GetExecuteFunction();
            long[] checkUserIds = userIds;

            Expression<Func<User, bool>> exp2 = m => true;
            List<UserNode> nodes = CacheService.ToCacheList<User, UserNode>(IdentityContract.Users, exp2, function);

            nodes.ForEach(m => m.IsChecked = checkUserIds.Contains(m.Id));
            return nodes;
        }

        /// <summary>
        /// 读取用户[角色]树
        /// </summary>
        /// <param name="roleId">角色编号</param>
        /// <returns>用户[角色]树数据</returns>
        [HttpGet]
        [ModuleInfo]
        [Description("读取[角色]树")]
        public virtual List<UserNode> ReadRoleUsers(long roleId)
        {
            Check.GreaterThan(roleId, nameof(roleId), 0);

            IFunction function = this.GetExecuteFunction();

            Expression<Func<UserRole, bool>> exp = m => m.RoleId.Equals(roleId);
            long[] checkUserIds = CacheService.ToCacheArray(IdentityContract.UserRoles, exp, m => m.UserId, function);

            //Expression<Func<User, bool>> exp2 = m => !m.IsLocked;
            Expression<Func<User, bool>> exp2 = m => true;
            List<UserNode> nodes = CacheService.ToCacheList<User, UserNode>(IdentityContract.Users, exp2, function);

            nodes.ForEach(m => m.IsChecked = checkUserIds.Contains(m.Id));
            return nodes;
        }

        /// <summary>
        /// 读取用户[组织机构]树
        /// </summary>
        /// <param name="organizationId">组织机构编号</param>
        /// <returns>用户[组织机构]树数据</returns>
        [HttpGet]
        [ModuleInfo]
        [Description("读取[组织机构]树")]
        public virtual List<UserOrganizationNode> ReadOrganizationUsers(long organizationId)
        {
            Check.GreaterThan(organizationId, nameof(organizationId), 0);

            IFunction function = this.GetExecuteFunction();

            Expression<Func<UserOrganization, bool>> exp = m => m.OrganizationId.Equals(organizationId);
            var userOrganizations = CacheService.ToCacheList(IdentityContract.UserOrganizations, exp, m => new { m.UserId, m.OrganizationId, m.Administrator, m.Leader }, function);

            Expression<Func<User, bool>> exp2 = m => !m.IsLocked;
            List<UserOrganizationNode> nodes = CacheService.ToCacheList(IdentityContract.Users, exp2, m => new UserOrganizationNode()
            {
                Id = m.Id,
                UserName = m.UserName,
                NickName = m.NickName,
                IsLocked = m.IsLocked,
                //IsChecked = userOrganizations.Exists(o => Equals(o.UserId, m.Id)),
                //Administrator = userOrganizations.Exists(o => Equals(o.UserId, m.Id)) ? userOrganizations.FirstOrDefault(o => Equals(o.UserId, m.Id)).Administrator : false,
                //Leader = userOrganizations.Exists(o => Equals(o.UserId, m.Id)) ? userOrganizations.FirstOrDefault(o => Equals(o.UserId, m.Id)).Leader : false,
            }, function);
            nodes.ForEach(m =>
            {
                m.IsChecked = userOrganizations.Exists(o => Equals(o.UserId, m.Id));
                m.Administrator = userOrganizations.FirstOrDefault(o => Equals(o.UserId, m.Id))?.Administrator == true;
                m.Leader = userOrganizations.FirstOrDefault(o => Equals(o.UserId, m.Id))?.Leader == true;
            });

            return nodes;
        }

        /// <summary>
        /// 新增用户信息
        /// </summary>
        /// <param name="dtos">用户信息</param>
        /// <returns>JSON操作结果</returns>
        [HttpPost]
        [ModuleInfo]
        [DependOnFunction(nameof(Read))]
        [DependOnFunction(nameof(ReadNode))]
        [DependOnFunction(nameof(GetUserNodes))]
        [UnitOfWork]
        [Description("新增")]
        public virtual async Task<AjaxResult> Create(params UserInputDto[] dtos)
        {
            Check.NotNull(dtos, nameof(dtos));
            List<string> names = new();
            foreach (var dto in dtos)
            {
                User user = dto.MapTo<UserInputDto, User>();
                IdentityResult result = dto.Password.IsMissing() ? await UserManager.CreateAsync(user) : await UserManager.CreateAsync(user, dto.Password);
                if (!result.Succeeded)
                {
                    return result.ToOperationResult().ToAjaxResult();
                }
                //电子证照
                var userPortfolio = user.Portfolio ?? new UserPortfolio();
                userPortfolio.UserId = user.Id;
                userPortfolio.Avatar = dto.Avatar.IsMissing() ? StaticHelper.GetImgBase64String(ImageName.CatAvatar) : dto.Avatar; ;
                userPortfolio.Signature = dto.Signature;
                var result2 = await UserPortfolioRepository.InsertOrUpdateAsync(new UserPortfolio[] { userPortfolio });
                if (!result2.Succeeded)
                {
                    return result2.ToAjaxResult();
                }
                //用户详细信息
                var userDetail = user.Detail ?? new UserDetail();
                userDetail.UserId = user.Id;
                userDetail.Gender = dto.Gender;
                userDetail.Birthday = dto.Birthday;
                userDetail.BloodType = dto.BloodType;
                userDetail.Tag = dto.Tag.ExpandAndToString(",");
                userDetail.Title = dto.Title.ExpandAndToString(",");
                userDetail.Address = dto.Address;
                userDetail.Profile = dto.Profile;
                userDetail.Sign = dto.Sign;
                userDetail.Remark = dto.Remark;
                userDetail.HomePath = dto.HomePath;
                result2 = await UserDetailRepository.InsertOrUpdateAsync(new UserDetail[] { userDetail });
                if (!result2.Succeeded)
                {
                    return result2.ToAjaxResult();
                }

                names.Add(user.UserName);
                dto.Id = user.Id;
            }
            return AjaxResult.Success(dtos, I18N.T("用户 {0} 创建成功", names.ExpandAndToString()));
        }

        /// <summary>
        /// 更新用户信息
        /// </summary>
        /// <param name="dtos">用户信息</param>
        /// <returns>JSON操作结果</returns>
        [HttpPost]
        [ModuleInfo]
        [DependOnFunction(nameof(Read))]
        [DependOnFunction(nameof(ReadNode))]
        [DependOnFunction(nameof(GetUserNodes))]
        [UnitOfWork]
        [Description("更新")]
        public virtual async Task<AjaxResult> Update(params UserInputDto[] dtos)
        {
            Check.NotNull(dtos, nameof(dtos));
            List<string> names = new();
            foreach (var dto in dtos)
            {
                User user = UserRepository.QueryAsNoTracking(o => o.Portfolio, o => o.Detail).Where(o => o.Id == dto.Id).FirstOrDefault();
                user = dto.MapTo(user);
                IdentityResult result = await UserManager.UpdateAsync(user);
                if (!result.Succeeded)
                {
                    return result.ToOperationResult().ToAjaxResult();
                }
                if (!dto.Password.IsMissing())
                {
                    var resetPasswordToken = await UserManager.GeneratePasswordResetTokenAsync(user);
                    result = await UserManager.ResetPasswordAsync(user, resetPasswordToken, dto.Password);
                    //UserManager.RemovePasswordAsync(user);
                    if (!result.Succeeded)
                    {
                        return result.ToOperationResult().ToAjaxResult();
                    }
                }
                //user = await UserManager.FindByIdAsync(user.Id.ToString());
                //电子证照
                var userPortfolio = user.Portfolio ?? new UserPortfolio();
                userPortfolio.UserId = user.Id;
                userPortfolio.Avatar = dto.Avatar.IsMissing() ? StaticHelper.GetImgBase64String(ImageName.CatAvatar) : dto.Avatar; ;
                userPortfolio.Signature = dto.Signature;
                var result2 = await UserPortfolioRepository.InsertOrUpdateAsync(new UserPortfolio[] { userPortfolio });
                if (!result2.Succeeded)
                {
                    return result2.ToAjaxResult();
                }
                //用户详细信息
                var userDetail = user.Detail ?? new UserDetail();
                userDetail.UserId = user.Id;
                userDetail.Gender = dto.Gender;
                userDetail.Birthday = dto.Birthday;
                userDetail.BloodType = dto.BloodType;
                userDetail.Tag = dto.Tag.ExpandAndToString(",");
                userDetail.Title = dto.Title.ExpandAndToString(",");
                userDetail.Address = dto.Address;
                userDetail.Profile = dto.Profile;
                userDetail.Sign = dto.Sign;
                userDetail.Remark = dto.Remark;
                userDetail.HomePath = dto.HomePath;
                result2 = await UserDetailRepository.InsertOrUpdateAsync(new UserDetail[] { userDetail });
                if (!result2.Succeeded)
                {
                    return result2.ToAjaxResult();
                }

                names.Add(user.UserName);
            }
            return AjaxResult.Success(I18N.T("用户 {0} 更新成功", names.ExpandAndToString()));
        }

        /// <summary>
        /// 删除用户信息
        /// </summary>
        /// <param name="ids">要删除的用户编号集合</param>
        /// <returns>JSON操作结果</returns>
        [HttpPost]
        [ModuleInfo]
        [DependOnFunction(nameof(Read))]
        [DependOnFunction(nameof(ReadNode))]
        [DependOnFunction(nameof(GetUserNodes))]
        [UnitOfWork]
        [Description("删除")]
        public virtual async Task<AjaxResult> Delete(params long[] ids)
        {
            Check.NotNull(ids, nameof(ids));
            List<string> names = new();
            foreach (long id in ids)
            {
                User user = await UserManager.FindByIdAsync(id.ToString());
                IdentityResult result = await UserManager.DeleteAsync(user);
                if (!result.Succeeded)
                {
                    return result.ToOperationResult().ToAjaxResult();
                }
                names.Add(user.UserName);
            }
            return AjaxResult.Success(I18N.T("用户 {0} 删除成功", names.ExpandAndToString()));
        }

        /// <summary>
        /// 设置用户角色
        /// </summary>
        /// <param name="dto">用户角色信息</param>
        /// <returns>JSON操作结果</returns>
        [HttpPost]
        [ModuleInfo]
        [DependOnFunction(nameof(Read))]
        [DependOnFunction(nameof(ReadNode))]
        [DependOnFunction(nameof(GetUserNodes))]
        [DependOnFunction(nameof(RoleController.ReadUserRoles), Controller = nameof(RoleController))]
        [UnitOfWork]
        [Description("设置角色")]
        public virtual async Task<AjaxResult> SetRoles(UserSetRoleDto dto)
        {
            Check.NotNull(dto, nameof(dto));

            OperationResult result = await IdentityContract.SetUserRoles(dto.UserId, dto.RoleIds);
            return result.ToAjaxResult();
        }

        /// <summary>
        /// 设置用户组织机构
        /// </summary>
        /// <param name="dto">用户组织机构信息</param>
        /// <returns>JSON操作结果</returns>
        [HttpPost]
        [ModuleInfo]
        [DependOnFunction(nameof(Read))]
        [DependOnFunction(nameof(ReadNode))]
        [DependOnFunction(nameof(GetUserNodes))]
        [DependOnFunction(nameof(OrganizationController.ReadUserOrganizations), Controller = nameof(OrganizationController))]
        [UnitOfWork]
        [Description("设置组织机构")]
        public virtual async Task<AjaxResult> SetOrganizations(UserSetOrganizationDto dto)
        {
            Check.NotNull(dto, nameof(dto));

            OperationResult result = await IdentityContract.SetUserOrganizations(dto.UserId, dto.UserOrganizations);
            return result.ToAjaxResult();
        }

        #endregion
    }
}